﻿using System;
using System.Math;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
            //---------------------------------------------------------
//TODO: Copiar estas asignaciones de evento en el constructor:
// después de InitializeComponents.
// Comprobar que los delegados usados son los correctos.
//---------------------------------------------------------
/*
BtnCrear.Click += new System.EventHandler(BtnCrear_Click_Click);
BtnFuncionObjetivo.Click += new System.EventHandler(BtnFO_Click);
BtnCalcular.Click += new System.EventHandler(BtnCalcular_Click);
RtnMin.Click += new System.EventHandler(RtnMin_Click);
RtnMax.Click += new System.EventHandler(RtnMax_Click);
TablaRestricciones.EditingControlShowing += new System.Windows.Forms.DataGridViewEditingControlShowingEventHandler(DGRestr_EditingControlShowing);
BtnNuevo.Click += new System.EventHandler(BtnNuevo_Click);
*/
//---------------------------------------------------------

        public string MM;
        int Tamc, Tamf, sigIgual, nrodIgual, xD, yD, xP, yP, c, f, CoL, RoW;
        // sigigual= pa redim matriz..... nroigual cantidad d filas agregadas
        //row y col.. tamaño d matriz del tablero completo
        string[,] Arreglo_Restricciones;
        string[,] MAtriz1;
        string[,] MAtrizF;
        double[] Funcion_Objetivo;
        bool P = false;
        bool D = false;
        bool idenXs = false;

        private void BtnCrear_Click_Click(System.Object sender, System.EventArgs e)
        {
            if (TxtVariables.Text != "" & TxtNroRest.Text != "" & TxtVariables.Text != "0" & TxtNroRest.Text != "0")
            {
                TablaRestricciones.ColumnCount = TxtVariables.Text + 2;
                TablaRestricciones.RowCount = TxtNroRest.Text;

                Tamf = TablaRestricciones.RowCount;
                Tamc = TablaRestricciones.ColumnCount - 3;
                for (I = 0; I <= Tamc; I++)
                {
                    TablaRestricciones.Columns[I].Name = "X" + Convert.ToInt32(I + 1);
                }
                TablaRestricciones.Columns[TablaRestricciones.ColumnCount - 2].Name = "Signo";
                TablaRestricciones.Columns[TablaRestricciones.ColumnCount - 1].Name = " LD  ";
                BtnFuncionObjetivo.Enabled = true;
            }
            else
            {
                MsgBox("Debe Completar Información", MsgBoxStyle.Critical);
                TxtVariables.Focus();
            }
            NroEnFilas();
            BtnCrear.Enabled = false;
            TablaRestricciones.Visible = true;
        }

        private void BtnFO_Click(System.Object sender, System.EventArgs e)
        {
            string r;
            string Pto;

            Arreglo_Restricciones = new string[Int(Tamf - 1), Convert.ToInt32(Tamc + 2)];
            if (TxtVariables.Text != "" & TxtNroRest.Text != "" & MM != "")
            {
                Funcion_Objetivo = new double[(Tamc + 1)];
                LblFO.Text = "";
                //validando inputbox
                for ( I = 0; I <= Tamc; I++)
                {
                    Pto = 0;
                    r = InputBox("Ingrese Coeficiente de X" + I + 1, "Función Objetivo", 1);
                    if ((r) == "") return;
                    if (Mid(r, 1, 1) == "-" | IsNumeric(Mid(r, 1, 1)) == true)
                    {
                        for (x = 2; x <= Len(r); x++)
                        {
                            if (Mid(r, x, 1) == ".") Pto = Pto + 1;
                            if (Pto == 0 | Pto == 2)
                            {
                                if (IsNumeric(Mid(r, x, 1)) == false)
                                {
                                    MsgBox("Debe Ingresar sólo números", MsgBoxStyle.Exclamation);
                                    return;
                                }
                            }
                            else if (Pto == 3)
                            {
                                MsgBox("Debe Ingresar sólo números", MsgBoxStyle.Exclamation);
                                return;
                            }
                            else if (Pto == 1)
                            {
                                Pto = Pto + 1;
                            }
                        }
                    }
                    else
                    {
                        MsgBox("Debe Ingresar sólo números", MsgBoxStyle.Exclamation);
                        return;
                    }
                    Funcion_Objetivo[I] = r;
                }

                for (I = 0; I < Funcion_Objetivo.Length; I++)
                {
                    if (Funcion_Objetivo[I] > 0)
                    {
                        LblFO.Text = LblFO.Text + " + " + Funcion_Objetivo[I] + "X" + I + 1;
                    }
                    else
                    {
                        LblFO.Text = LblFO.Text + " - " + Mid(Funcion_Objetivo[I], 2, Len(Funcion_Objetivo[I])) + "X" + I + 1;
                    }
                }
                LblFO.Text = MM + " " + LblFO.Text;
                BtnFuncionObjetivo.Enabled = false;
                BtnCalcular.Enabled = true;
            }
            else
            {
                MsgBox("Debe seleccionar Maximizar o Minimizar", MsgBoxStyle.Information, "Función Objetivo");
                RtnMax.Focus();
            }
        }

        private string Mid(string r, int p, int p_3)
        {
            throw new NotImplementedException();
        }

        private void BtnCalcular_Click(System.Object sender, System.EventArgs e)
        {
            int m;
            sigIgual = -1;
            nrodIgual = 0;
            if (MM == "MIN")
            {
                for (i = 0; i <= Tamc; i++)
                {
                    System.Globalization.NumberFormatInfo nfi_g0 = new System.Globalization.NumberFormatInfo();
                    nfi_g0.CurrencyGroupSeparator = ".";
                    Funcion_Objetivo[i] = Convert.ToDouble(Funcion_Objetivo[i, nfi_g0]) * (-1);
                    MM = "MAX";
                }
            }
            for (j = 0; j < Tamf; j++)
            {
                for (i = 0; i <= Tamc + 2; i++)
                {
                    if (TablaRestricciones[i, j].Value == "")
                    {
                        MsgBox("Debe ingresar las Restricciones", MsgBoxStyle.Critical, "Método Simplex");
                        return;
                    }
                }
            }
            TablaRestricciones.ReadOnly = true;
            BtnCalcular.Enabled = false;
            for (i = 0; i < Tamf; i++)
            {
                if (TablaRestricciones[Tamc + 1, i].Value == "=")
                {
                    sigIgual = sigIgual + 1;
                }
            }
            Arreglo_Restricciones = new string[Int(Tamf + sigIgual), Convert.ToInt32(Tamc + 2)];

            for (i = 0; i < Tamf; i++)
            {
                if (Arreglo_Restricciones[m, 0] != "")
                {
                    m = m + 1;
                    i = i - 1;
                }
                else
                {
                    if (TablaRestricciones[Tamc + 1, i].Value == ">=")
                    {
                        for (n = 0; n <= Tamc; n++)
                        {
                            Arreglo_Restricciones[m, n] = -1 * TablaRestricciones[n, i].Value;
                        }
                        Arreglo_Restricciones[m, Tamc + 1] = -1 * TablaRestricciones[Tamc + 2, i].Value;
                        Arreglo_Restricciones[m, Tamc + 2] = "S" + m + 1;
                        m = i;
                    }
                    else if (TablaRestricciones[Tamc + 1, i].Value == "=")
                    {
                        for (n = 0; n <= Tamc; n++)
                        {
                            Arreglo_Restricciones[m, n] = TablaRestricciones[n, i].Value;
                            Arreglo_Restricciones[m + 1, n] = -1 * TablaRestricciones[n, i].Value;
                        }
                        Arreglo_Restricciones[m, Tamc + 1] = TablaRestricciones[Tamc + 2, i].Value;
                        Arreglo_Restricciones[m, Tamc + 2] = "H" + m + 1;
                        Arreglo_Restricciones[m + 1, Tamc + 1] = -1 * TablaRestricciones[Tamc + 2, i].Value;
                        Arreglo_Restricciones[m + 1, Tamc + 2] = "S" + m + 2;
                        nrodIgual = nrodIgual + 1;
                    }
                    else
                    {
                        for (n = 0; n <= Tamc; n++)
                        {
                            Arreglo_Restricciones[m, n] = TablaRestricciones[n, i].Value;
                        }
                        Arreglo_Restricciones[m, Tamc + 1] = TablaRestricciones[Tamc + 2, i].Value;
                        Arreglo_Restricciones[m, Tamc + 2] = "H" + m + 1;
                        m = i;
                    }
                }
            }
            CoL = Tamc + 3;
            RoW = Tamf + 2 + nrodIgual;
            Tablero();
            if (D == false & P == false)
            {
                MsgBox("No tiene solucion", MsgBoxStyle.Exclamation, "Simplex");
                //BtnSensibilidad.Enabled = False
                return;
            }
            while (true)
            {
                if (D == true & P == true)
                {
                    MContribucion();
                }
                if (P == true)
                {
                    c = xP;
                    f = yP;
                    SimPlex();
                    P = false;
                    //MsgBox("primal")
                }
                else if (D == true)
                {
                    c = xD;
                    f = yD;
                    SimPlex();
                    D = false;
                    //MsgBox("dual")
                }
                //completando datos
                for (i = 0; i <= CoL; i++)
                {
                    for (j = 0; j <= RoW; j++)
                    {
                        MAtriz1[j, i] = MAtrizF[j, i];
                    }
                }
                Primal();
                Dual();
            } while ((D == true | P == true)) ;
            if (D == false & P == false)
            {
                tabFinal();
            }
            //BtnSensibilidad.Enabled = True
        }
        internal void SimPlex()
        {
            //c=col ... f=fila coordenadas dl var d entrant con variabl salient
            MAtrizF = new string[RoW, CoL];
            MAtrizF[f, c] = (MAtriz1[f, c]) ^ -1; //pivot
            //intercambiando vars
            for (j = 0; j <= 1; j++)
            {
                MAtrizF[j, c] = MAtriz1[f, j];
                MAtrizF[f, j] = MAtriz1[j, c];
            }
            //vars entrants -> columna
            for (j = 2; j <= RoW; j++)
            {
                if (j != f)
                {
                    MAtrizF[j, c] = -1 * (MAtriz1[j, c]) / (MAtriz1[f, c]);
                }
            }
            //vars salients-> fila
            for (i = 2; i <= CoL; i++)
            {
                if (i != c)
                {
                    MAtrizF[f, i] = (MAtriz1[f, i]) / (MAtriz1[f, c]);
                }
            }
            //regla simple pa casilleros en matriz
            for (i = 2; i <= CoL; i++)
            {
                if (i != c)
                {
                    for (j = 2; j <= RoW; j++)
                    {
                        if (j != f)
                        {
                            MAtrizF[j, i] = (MAtriz1[j, i]) - (((MAtriz1[j, c]) * (MAtriz1[f, i])) / (MAtriz1[f, c]));
                        }
                    }
                }
            }
            //completando datos
            for (i = 0; i <= CoL; i++)
            {
                for (j = 0; j <= RoW; j++)
                {
                    if (MAtrizF[j, i] == "")
                    {
                        MAtrizF[j, i] = MAtriz1[j, i];
                    }
                }
            }

        }
        private void tabFinal()
        { //del tablero final evaluar LD y Zj positivos pa hallar opti y facti
            int LDp, ZJp;
            //valores LD positivos
            for (j = 2; j < RoW; j++)
            {
                if (MAtrizF[j, CoL] >= 0)
                {
                    LDp = LDp + 1;
                }
            }
            if (LDp != (RoW - 2))
            {
                LblComentario.Text = LblComentario.Text + "- No es Factible -";
                //BtnSensibilidad.Enabled = False
            }
            //valores ZJ positivos
            for (i = 2; i < CoL; i++)
            {
                if (MAtrizF[RoW, i] > 0)
                {
                    ZJp = ZJp + 1;
                }
            }
            if (ZJp != (CoL - 2))
            {
                LblComentario.Text = LblComentario.Text + "- No es Optimo -";
                //BtnSensibilidad.Enabled = False
            }
            //todos positivos.. OPTIMO
            if (LDp == (RoW - 2) & ZJp == (CoL - 2))
            {
                MsgBox("Tablero Optimo", MsgBoxStyle.Exclamation, "Simplex");
                idenXs = true;
                if (Mid(LblFO.Text, 1, 3) == "MIN")
                {
                    LblZ.Text = "Valor de Z = " + -1 * System.String.Format(Val(MAtrizF[RoW, CoL]), "0.00");
                }
                else
                {
                    LblZ.Text = "Valor de Z = " + System.String.Format(Val(MAtrizF[RoW, CoL]), "0.00");
                }
            }
            MostrarTablero();
        }
        private void MostrarTablero()
        {
            //DGResul.ColumnCount = 0
            //DGResul.RowCount = 0
            TablaResultado.ColumnCount = CoL + 1;
            TablaResultado.RowCount = RoW + 1;

            for (i = 0; i <= CoL; i++)
            {
                for (j = 0; j <= RoW; j++)
                {
                    if (i > 1 & j > 1)
                    {
                        TablaResultado[i, j].Value = System.String.Format(Val(MAtrizF[j, i]), "0.00");
                    }
                    else
                    {
                        TablaResultado[i, j].Value = MAtrizF[j, i];
                    }
                }
            }

            //IDENTIFICANDO VARIABLES Xs
            if (idenXs == true)
            {
                for (j = 2; j < RoW; j++)
                {
                    if (Mid(MAtrizF[j, 1], 1, 1) == "X")
                    {
                        LblXs.Text = LblXs.Text + "   " + MAtrizF[j, 1] + " = " + System.String.Format(Val(MAtrizF[j, CoL]), "0.00");
                    }
                }
                for (I = 2; I < CoL; I++)
                {
                    if (Mid(MAtrizF[1, I], 1, 1) == "X")
                    {
                        LblXs.Text = LblXs.Text + "   " + MAtrizF[1, I] + " = 0 ";
                    }
                }
                TablaResultado.Visible = true;
                //BtnSensibilidad.Enabled = True
            }
            else
            {
                MsgBox("No tiene solución", MsgBoxStyle.Exclamation, "Simplex");
                //BtnSensibilidad.Enabled = False
            }
        }
        private void Primal()
        {
            int AuxP; //i,x=col ... j,y=fila
            xP = 0;
            yP = 0;
            if (P == false)
            {
                //valores zj negativos
                for (i = 2; i < CoL; i++)
                {
                    if (MAtriz1[RoW, i] < 0)
                    {
                        if (AuxP > MAtriz1[RoW, i])
                        {
                            AuxP = MAtriz1[RoW, i];
                            xP = i;
                        }
                    }
                }
                //hallando pivote primal
                if (AuxP < 0)
                {
                    AuxP = 0;
                    for (j = 2; j < RoW; j++)
                    {
                        if (MAtriz1[j, xP] > 0)
                        {
                            if (MAtriz1[j, CoL] >= 0)
                            {
                                if (AuxP == 0)
                                {
                                    System.Globalization.NumberFormatInfo nfi_g1 = new System.Globalization.NumberFormatInfo();
                                    nfi_g1.CurrencyGroupSeparator = ".";
                                    AuxP = Abs(Val(MAtriz1[j, CoL]) / Convert.ToDouble(MAtriz1[j, xP, nfi_g1]));
                                    yP = j;
                                    P = 1;
                                    System.Globalization.NumberFormatInfo nfi_g2 = new System.Globalization.NumberFormatInfo();
                                    nfi_g2.CurrencyGroupSeparator = ".";
                                }
                                else if (AuxP > Abs((Val(MAtriz1[j, CoL]) / Convert.ToDouble(MAtriz1[j, xP, nfi_g2]))))
                                {
                                    System.Globalization.NumberFormatInfo nfi_g3 = new System.Globalization.NumberFormatInfo();
                                    nfi_g3.CurrencyGroupSeparator = ".";
                                    AuxP = Abs(Val(MAtriz1[j, CoL]) / Convert.ToDouble(MAtriz1[j, xP, nfi_g3]));
                                    yP = j;
                                    P = 1;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                MsgBox("primal");
            }
            //MsgBox(P & " " & MAtriz1(yP, n) & " " & MAtriz1(m, xP) & " " & MAtriz1(yP, xP))

        }

        private void Dual()
        {
            int AuxD = 0; //i,x=col ... j,y=fila .... x,y fijos
            bool vNeg = false;
            xD = 0;
            yD = 0;
            if (D == false)
            {
                //valores LD negativos
                for (j = 2; j < RoW; j++)
                {
                    if (MAtriz1[j, CoL] <= 0)
                    {
                        if (AuxD > MAtriz1[j, CoL])
                        {
                            AuxD = MAtriz1[j, CoL];
                            yD = j;
                        }
                    }
                }
                //valores ZJ positivos
                for (i = 2; i < CoL; i++)
                {
                    if (MAtriz1[RoW, i] > 0)
                    {
                        vNeg = true;
                    }
                }

                if (vNeg == false | yD == 0)
                {
                    //MsgBox(D & " " & MAtriz1(yD, CoL) & " " & MAtriz1(RoW, xD) & " " & MAtriz1(yD, xD))
                    return;
                }

                if (AuxD < 0)
                {
                    AuxD = 0;
                    for (i = 2; i < CoL; i++)
                    {
                        if (MAtriz1[yD, i] < 0)
                        {
                            if (MAtriz1[RoW, i] >= 0)
                            {
                                if (AuxD == 0)
                                {
                                    System.Globalization.NumberFormatInfo nfi_g4 = new System.Globalization.NumberFormatInfo();
                                    nfi_g4.CurrencyGroupSeparator = ".";
                                    AuxD = Abs(Val(MAtriz1[RoW, i]) / Convert.ToDouble(MAtriz1[yD, i, nfi_g4]));
                                    xD = i;
                                    D = true;
                                    System.Globalization.NumberFormatInfo nfi_g5 = new System.Globalization.NumberFormatInfo();
                                    nfi_g5.CurrencyGroupSeparator = ".";
                                }
                                else if (AuxD > Abs(Val(MAtriz1[RoW, i]) / Convert.ToDouble(MAtriz1[yD, i, nfi_g5])))
                                {
                                    System.Globalization.NumberFormatInfo nfi_g6 = new System.Globalization.NumberFormatInfo();
                                    nfi_g6.CurrencyGroupSeparator = ".";
                                    AuxD = Abs(Val(MAtriz1[RoW, i]) / Convert.ToDouble(MAtriz1[yD, i, nfi_g6]));
                                    xD = i;
                                    D = true;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                MsgBox("dual");
            }
            //MsgBox(D & " " & MAtriz1(yD, n) & " " & MAtriz1(m, xD) & " " & MAtriz1(yD, xD))
            //MsgBox(PivoteD & " " & D & " " & MAtriz1(m, xD) & " " & LD)
        }
        private void NroEnFilas()
        {
            int rowNumber = 1;
            foreach (DataGridViewRow row in TablaRestricciones.Rows)
            {
                if (row.IsNewRow) continue;
                row.HeaderCell.Value = rowNumber.ToString;
                rowNumber = rowNumber + 1;
            }
            //DGRestr.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders)
            TablaRestricciones.RowHeadersWidth = 40;
        }
        private void Tablero()
        {
            //i=col ... j=fila
            MAtriz1 = new string[Int(RoW), Convert.ToInt32(CoL)];
            //almacenando el vector de funcion objetivo FO. y zj
            for (i = 0; i < Funcion_Objetivo.Length; i++)
            {
                MAtriz1[0, i + 2] = Funcion_Objetivo[i];
                MAtriz1[RoW, i + 2] = -1 * Funcion_Objetivo[i];
            }
            //almacenando las restriccions
            for (j = 0; j <= Tamf + sigIgual; j++)
            {
                for (i = 0; i <= Tamc + 1; i++)
                {
                    MAtriz1[j + 2, i + 2] = Arreglo_Restricciones[j, i];
                    MAtriz1[j + 2, 1] = Arreglo_Restricciones[j, Tamc + 2];
                }
            }
            //almacenando las nombre variabls Xi restriccions
            for (i = 0; i <= Tamc; i++)
            {
                MAtriz1[1, i + 2] = TablaRestricciones.Columns[i].Name;
            }
            //completando con 0
            for (j = 2; j < RoW; j++)
            {
                MAtriz1[j, 0] = "0";
            }
            Primal();
            Dual();
        }
        private void MContribucion()
        {
            int MCont;
            if (P == true & D == true)
            {
                P = false;
                D = false;
                MCont = Abs((MAtriz1[RoW, xP] / MAtriz1[yP, xP]) * MAtriz1[yP, CoL]);
                if (MCont < Abs((MAtriz1[RoW, xD] / MAtriz1[yD, xD]) * MAtriz1[yD, CoL]))
                {
                    MCont = Abs((MAtriz1[RoW, xD] / MAtriz1[yD, xD]) * MAtriz1[yD, CoL]);
                    D = true;
                }
                else
                {
                    P = true;
                }
            }

        }
        //para validacion de datagridview
        private void DGRestr_EditingControlShowing(object sender, System.Windows.Forms.DataGridViewEditingControlShowingEventArgs e)
        {
            // referencia a la celda
            TextBox validar = ((TextBox)e.Control);

            // agregar el controlador de eventos para el KeyPress
            validar.KeyPress += new /* TODO: Comprobar el tipo de delegado */ EventHandler(validar_Keypress);
        }
        //evento Keypress
        ///''''''''''''''''
        private void validar_Keypress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            char caracter = e.KeyChar;
            int columna = TablaRestricciones.CurrentCell.ColumnIndex;

            // comprobar si la celda en edición corresponde a la columna del signo
            if (columna == Tamc + 1)
            {
                // Obtener caracter
                // comprobar si el caracter es un número o el retroceso
                if (!(Asc(e.KeyChar) == 60 | Asc(e.KeyChar) == 61 | Asc(e.KeyChar) == 62 | (caracter == (char)(Keys.LShiftKey)) & (caracter == (char)(Keys.RShiftKey)) | (caracter == (char)(Keys.Back))))
                {
                    e.KeyChar = (char)(0);
                }

            }
            else
            {
                // comprobar si el caracter es un número o el retroceso
                //If Char.IsNumber(caracter) Or (caracter = (char)(Keys.Back)) Or (Asc(e.KeyChar) = 46) Or ((Asc(e.KeyChar) = 45)) Then
                //    ' (Asc(e.KeyChar) = 45) ' para escribir negativo -
                //    If (((Asc(e.KeyChar) = 45))) Then
                //        If SnEg = False Then
                //            SnEg = True
                //        Else
                //            e.KeyChar = (char)(0)
                //        End If
                //    End If
                //Else
                //    e.KeyChar = (char)(0)
                //End If
                if (!Char.IsNumber(caracter) & (caracter == (char)(Keys.Back)) == false & !((Asc(e.KeyChar) == 46) | ((Asc(e.KeyChar) == 45))))
                {
                    // (Asc(e.KeyChar) = 45) ' pa scribir negativo -
                    e.KeyChar = (char)(0);
                }
            }
        }

       private void BtnCrear_Click(object sender, EventArgs e)
        {

        }

        private void BtnNuevo_Click_1(object sender, EventArgs e)
        {
            TxtNroRest.Text = "";
            TxtVariables.Text = "";
            TablaRestricciones.Visible = false;
            TablaResultado.Visible = false;
            LblComentario.Text = "";
            LblFO.Text = "";
            LblXs.Text = "";
            LblZ.Text = "";
            BtnCrear.Enabled = true;
        }

        private void BtnFuncionObjetivo_Click(object sender, EventArgs e)
        {

        }

        private void BtnCalcular_Click_1(object sender, EventArgs e)
        {

        }

        private void RtnMax_CheckedChanged(object sender, EventArgs e)
        {
            MM = "MAX";
        }

        private void RtnMin_CheckedChanged(object sender, EventArgs e)
        {
            MM = "MIN";
        }
        }
    }
   
